<?php

namespace app\common\services\weixin;

use app\common\components\HttpClient;
use app\common\services\applog\ApplogService;
use Yii;
use yii\log\FileTarget;

/**
 * Class PayApiService 支付服务
 * 主要做微信pay 相关的事情都放到该文件中
 * Author: yanhaoqiang
 * @package app\common\services\weixin
 */
class PayApiService {
    private $params = [];
    private $wxpay_params = [];
    private $prepay_id = null;
    public $prepay_info = null;

    public function __construct($wxpay_params) {
        $this->wxpay_params = $wxpay_params;
    }

    /**
     * [setWxpay_params 设置微信参数]
     * @param $wxpay_params
     * @return void
     */
    public function setWxpay_params($wxpay_params) {
        $this->wxpay_params = $wxpay_params;
    }

    /**
     * [setParameter 设置普通参数]
     * 因为这些参数都是通过参数传递过来的,所以定义该方法供外接调用
     * @param $parameter
     * @param $parameterValue
     * @return void
     */
    function setParameter($parameter, $parameterValue) {
        $this->params[$parameter] = $parameterValue;
    }

    /**
     * [getPrepayInfo 获取支付xml]
     * 根据微信定义的规则组装好数据进行传递
     * @return bool|mixed
     */
    public function getPrepayInfo() {
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $this->params["nonce_str"] = $this->createNoncestr();//随机字符串
        $this->params["sign"] = $this->getSign($this->params);//签名算法生成签名信息

        //最终要发送一个xml信息,所有这里拼接xml,然后发送
        $xml_data = $this->arrayToXml($this->params);
        $ret = HttpClient::post($url, $xml_data);
        if ($ret) {
            //微信返回的也是一个xml,这里需要将其转换为array
            $wx_order = $this->xmlToArray($ret);
            $this->prepay_info = $wx_order;
            //打印log 信息
            $this->record_xml(var_export($wx_order, true));
            if (isset($wx_order['result_code']) && $wx_order['result_code'] == 'SUCCESS') {
                return $wx_order;
            }
        }
        return false;
    }

    /**
     * [createNoncestr 生成一个随机字符串]
     * @param int $length
     * @return string
     */
    private function createNoncestr($length = 32) {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    /**
     * [getSign 微信支付指定的签名算法, 一个字符串]
     * 获取签名入口函数
     * @param $Obj
     * @return string
     */
    private function getSign($Obj) {
        foreach ($Obj as $k => $v) {
            $Parameters[$k] = $v;
        }
        ksort($Parameters);
        $String = $this->formatBizQueryParaMap($Parameters, false);//生成一个字符串
        $String = $String . "&key=" . $this->wxpay_params['pay']['key'];
        $String = md5($String);//md5 加密操作
        $result_ = strtoupper($String);//大写操作
        return $result_;
    }

    /**
     * [formatBizQueryParaMap 格式化参数，签名过程需要使用]
     * 按微信规则组装参数
     * @param $paraMap
     * @param $urlencode
     * @return string
     */
    private function formatBizQueryParaMap($paraMap, $urlencode) {
        $buff = "";
        ksort($paraMap);
        foreach ($paraMap as $k => $v) {
            if ($urlencode) {
                $v = urlencode($v);
            }
            //$buff .= strtolower($k) . "=" . $v . "&";
            $buff .= $k . "=" . $v . "&";
        }
        $reqPar = '';
        if (strlen($buff) > 0) {
            $reqPar = substr($buff, 0, strlen($buff) - 1);
        }
        return $reqPar;
    }

    /**
     * [getParameters 设置jsapi, 在线支付相关参数]
     * @return mixed
     */
    public function getParameters() {
        $jsApiObj["appId"] = $this->wxpay_params['appid'];
        $timeStamp = time();
        $jsApiObj["timeStamp"] = $timeStamp;
        $jsApiObj["nonceStr"] = $this->createNoncestr();
        $jsApiObj["package"] = "prepay_id=" . $this->prepay_id;
        $jsApiObj["signType"] = "MD5";
        $jsApiObj["paySign"] = $this->getSign($jsApiObj);
        return $jsApiObj;
    }

    /**
     * [arrayToXml array转xml]
     * @param $arr
     * @return string
     */
    public function arrayToXml($arr) {
        $xml = "<xml>";
        foreach ($arr as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";

            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    /**
     * [xmlToArray 将xml转为array]
     * @param $xml
     * @return mixed
     */
    public function xmlToArray($xml) {
        //将XML转为array
        //simplexml_load_string 从字符串转换为objet 对象
        $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $array_data;
    }

    /**
     * [record_xml 记录xml 信息]
     * @param $xml
     * @return void
     */
    private function record_xml($xml) {
        $log = new FileTarget();
        $log->logFile = Yii::$app->getRuntimePath() . "/logs/wxpay_sign_" . date("Ymd") . ".log";
        $log->messages[] = [
            "[url:{$_SERVER['REQUEST_URI']}],[xml data:{$xml}]",
            1,
            'application',
            time()
        ];
        $log->export();
    }

    /**
     * [setPrepayId ]
     * @param $prepay_id
     * @return void
     */
    function setPrepayId($prepay_id) {
        $this->prepay_id = $prepay_id;
    }

    /**
     * [getSignParams ]
     * @return array
     */
    public function getSignParams() {
        $this->params["nonce_str"] = $this->createNoncestr();//随机字符串
        $this->params["sign"] = $this->getSign($this->params);//签名
        return $this->params;
    }

    /**
     * [checkSign 检查签名]
     * @param $sign
     * @return bool
     */
    function checkSign($sign) {
        $tmpData = $this->params;
        $wxpay_sign = $this->getSign($tmpData);//本地签名

        if ($wxpay_sign == $sign) {
            return true;
        }
        return false;
    }

}